package io.gitee.chearnee.fw.openapi;

import com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler;
import io.gitee.chearnee.fw.openapi.config.OpenApiProperties;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.type.TypeHandlerRegistry;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.util.ClassUtils;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

import static org.springframework.util.StringUtils.tokenizeToStringArray;

/**
 * @author cn
 * @version 1.0
 * @description
 * @date 2021/9/17 19:54
 */
@Slf4j
//@Configuration
@ComponentScan
@EnableConfigurationProperties(OpenApiProperties.class)
@MapperScan(basePackages = "io.gitee.chearnee.openapi.business.mapper")
@RequiredArgsConstructor
//@EnableAspectJAutoProxy
public class OpenApiAutoConfiguration {

  private final SqlSessionFactory sessionFactory;

  @PostConstruct
  @SneakyThrows
  public void setMybatisPlusProperties() {
    // 取得类型转换注册器
    TypeHandlerRegistry typeHandlerRegistry = sessionFactory.getConfiguration()
        .getTypeHandlerRegistry();
    Set<Class<?>> classes = scanClasses("io.gitee.chearnee.openapi.constant.enums", null);
    classes.stream()
        .filter(Class::isEnum)
        .filter(MybatisEnumTypeHandler::isMpEnums)
        .forEach(cls -> typeHandlerRegistry.register(cls, MybatisEnumTypeHandler.class));
  }

  private Set<Class<?>> scanClasses(String packagePatterns, Class<?> assignableType)
      throws IOException {
    ResourcePatternResolver RESOURCE_PATTERN_RESOLVER = new PathMatchingResourcePatternResolver();
    MetadataReaderFactory METADATA_READER_FACTORY = new CachingMetadataReaderFactory();
    Set<Class<?>> classes = new HashSet<>();
    String[] packagePatternArray = tokenizeToStringArray(packagePatterns,
        ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
    for (String packagePattern : packagePatternArray) {
      Resource[] resources = RESOURCE_PATTERN_RESOLVER
          .getResources(ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
              + ClassUtils.convertClassNameToResourcePath(packagePattern) + "/**/*.class");
      for (Resource resource : resources) {
        try {
          ClassMetadata classMetadata = METADATA_READER_FACTORY.getMetadataReader(resource)
              .getClassMetadata();
          Class<?> clazz = Resources.classForName(classMetadata.getClassName());
          if (assignableType == null || assignableType.isAssignableFrom(clazz)) {
            classes.add(clazz);
          }
        } catch (Throwable e) {
          log.warn("Cannot load the '" + resource + "'. Cause by " + e);
        }
      }
    }
    return classes;
  }
}
